package repository

import (
	"context"
	"database/sql"
	"fmt"
	"strconv"
	"strings"

	"mall/common/enumx"
	"mall/common/modelx"
	"mall/service/blog/model"

	"github.com/sirupsen/logrus"
	"github.com/volatiletech/sqlboiler/v4/boil"
	"github.com/volatiletech/sqlboiler/v4/queries"
	"github.com/volatiletech/sqlboiler/v4/queries/qm"
	"github.com/zeromicro/go-zero/core/stores/cache"
)

type (
	// BlogTermRepository is an interface to be customized, add more methods here,
	// and implement the added methods in customBlogTermRepository.
	BlogTermRepository interface {
		Conn() error
		FindOne(ctx context.Context, id int64, cols []string) (*model.BlogTerm, error) /////
		GetList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogTerm, int64, error) /////
		GetRelationshipList(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogTermRelationship, int64, error) ///// 根据分类或标签获取对应的文章或页面、根据文章或分页获取对应的分类和标签
		Insert(
			ctx context.Context,
			term *model.BlogTerm,
			meta []*model.BlogTermMetum,
			extra *model.BlogExtra,
		) error /////
		Update(
			ctx context.Context,
			term *model.BlogTerm,
			meta []*model.BlogTermMetum,
			extra *model.BlogExtra,
		) (int64, error) /////
		DeleteBatch(ctx context.Context, ids []uint64) (int64, error)  // deprecated
		GetMeta(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogTermMetum, int64, error) /////
		GetMedia(
			ctx context.Context,
			cols model.M,
			withCount int,
			filter map[string]map[string][]any,
		) ([]*model.BlogAttachmentRelationship, int64, error) /////
		IncreaseMeta(ctx context.Context, tids []int64, metaKey string, step int) error /////
		DecreaseMeta(ctx context.Context, tids []int64, metaKey string, step int) error /////
		DiagnoseMedia(ctx context.Context, ids []uint64) (int64, error) //////
		DiagnoseDetail(ctx context.Context, ids []uint64) (int64, error) //////
		DiagnoseMetum(ctx context.Context, ids []uint64) (int64, error) /////
		DiagnoseTerm(ctx context.Context, ids []uint64) (int64, error) /////
		DiagnoseRelationship(ctx context.Context, ids []uint64) (int64, error) /////
		SyncQiniu(ctx context.Context, id uint64, mediaId uint64, url string) (int64, error)
	}

	customBlogTermRepository struct {
		cacheConf  cache.CacheConf
		dataSource string

		mysqlConn *sql.DB
	}

	// Custom struct for selecting a subset of data
	RandomInfo struct {
		MaxId int     `boil:"max_id"`
		MinId int     `boil:"min_id"`
		Rand  float64 `boil:"rand"`
	}
)

// NewBlogTermRepository returns a repository for the database table.
func NewBlogTermRepository(dataSource string, cacheConf cache.CacheConf) BlogTermRepository {
	return &customBlogTermRepository{
		cacheConf:  cacheConf,
		dataSource: dataSource,
	}
}

func (r *customBlogTermRepository) Conn() error {
	if r.mysqlConn == nil {
		mysqlConn, err := modelx.NewMysqlConn(r.dataSource)
		if err != nil {
			return err
		}

		r.mysqlConn = mysqlConn
	}

	return nil
}

func (r *customBlogTermRepository) FindOne(
	ctx context.Context,
	id int64,
	cols []string,
) (term *model.BlogTerm, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	term, err = model.FindBlogTerm(ctx, r.mysqlConn, uint64(id), cols...)
	if err == sql.ErrNoRows {
		return nil, model.ErrNotFound
	}

	return
}

func (r *customBlogTermRepository) GetList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogTerm, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogTermColumns.TermID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermColumns.TermID, opMap)...)
			case model.BlogTermColumns.Name:
				mods = append(mods, modelx.GetStringMods(model.BlogTermColumns.Name, opMap)...)
			case model.BlogTermColumns.Slug:
				mods = append(mods, modelx.GetStringMods(model.BlogTermColumns.Slug, opMap)...)
			case model.BlogTermColumns.Taxonomy:
				mods = append(mods, modelx.GetIntMods(model.BlogTermColumns.Taxonomy, opMap)...)
			case model.BlogTermColumns.ParentID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermColumns.ParentID, opMap)...)
			case model.BlogTermColumns.TermGroup:
				mods = append(mods, modelx.GetIntMods(model.BlogTermColumns.TermGroup, opMap)...)
			case model.BlogTermColumns.Count:
				mods = append(mods, modelx.GetIntMods(model.BlogTermColumns.Count, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods) + 3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.BlogTermColumns.TermID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset - 1))
				previousList, previousErr := model.BlogTerms(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}
				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset + limit))
				nextList, nextErr := model.BlogTerms(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}
				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount * 2
		} else {
			count, err = model.BlogTerms(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogTermColumns.TermID)
		columns = append(columns, model.BlogTermColumns.Taxonomy)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogTerms(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogTermRepository) GetRelationshipList(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogTermRelationship, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var offset int
	var limit int
	var selectCol string
	var random bool
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "offset":
			if val, ok := v.(int32); ok && val > 0 {
				offset = int(val)
			}
		case "limit":
			if val, ok := v.(int32); ok && val > 0 {
				limit = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		case "random":
			if val, ok := v.(string); ok && val == "1" {
				random = true
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogTermRelationshipColumns.TermRelationshipID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.TermRelationshipID, opMap)...)
			case model.BlogTermRelationshipColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.ObjectID, opMap)...)
			case model.BlogTermRelationshipColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.ObjectType, opMap)...)
			case model.BlogTermRelationshipColumns.TermID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.TermID, opMap)...)
			case model.BlogTermRelationshipColumns.StickyType:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.StickyType, opMap)...)
			case model.BlogTermRelationshipColumns.TermOrder:
				mods = append(mods, modelx.GetIntMods(model.BlogTermRelationshipColumns.TermOrder, opMap)...)
			}
		}
	}

	if random {
		subMods := make([]qm.QueryMod, len(mods), len(mods) + 2)
		copy(subMods, mods)
		subMods = append(subMods, qm.Select(fmt.Sprintf(
			"max(%s) as max_id, min(%s) as min_id, RAND() as rand",
			model.BlogTermRelationshipColumns.ObjectID,
			model.BlogTermRelationshipColumns.ObjectID,
		)))
		subMods = append(subMods, qm.From(model.TableNames.BlogTermRelationships))

		var info RandomInfo
		// Use query building
		err = model.NewQuery(subMods...).Bind(ctx, r.mysqlConn, &info)
		if err != nil {
			return
		}

		rand := int(float64(info.MaxId - info.MinId) * info.Rand) + info.MinId
		mods = append(mods, model.BlogTermRelationshipWhere.ObjectID.GTE(uint64(rand)))
		mods = append(mods, qm.Distinct(model.BlogTermRelationshipColumns.ObjectID))

		if pageSize > 0 {
			mods = append(mods, qm.Limit(pageSize))
		}

		var columns []string
		if selectCol != "" {
			columns = strings.Split(selectCol, ",")
		}
		if len(columns) > 0 {
			mods = append(mods, qm.Select(columns...))
		}

		list, err = model.BlogTermRelationships(mods...).All(ctx, r.mysqlConn)
		return
	}

	if withCount >= 0 {
		if withCount >= 2 {
			var nextCount int64
			var previousCount int64
			subMods := make([]qm.QueryMod, len(mods), len(mods) + 3)
			copy(subMods, mods)
			subMods = append(subMods, qm.Limit(1))
			subMods = append(subMods, qm.Select(model.BlogTermRelationshipColumns.TermRelationshipID))

			if withCount != 3 && offset >= 1 {
				subMods = append(subMods, qm.Offset(offset - 1))
				previousList, previousErr := model.BlogTermRelationships(subMods...).All(ctx, r.mysqlConn)
				if previousErr != nil {
					err = previousErr
					return
				}
				if len(previousList) > 0 {
					previousCount = 1
				}
			}
			if limit > 0 {
				subMods = append(subMods, qm.Offset(offset + limit))
				nextList, nextErr := model.BlogTermRelationships(subMods...).All(ctx, r.mysqlConn)
				if nextErr != nil {
					err = nextErr
					return
				}
				if len(nextList) > 0 {
					nextCount = 1
				}
			}

			count = previousCount + nextCount * 2
		} else {
			count, err = model.BlogTermRelationships(mods...).Count(ctx, r.mysqlConn)
			if err != nil {
				return
			}

			if withCount == 0 {
				return
			}
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	} else if limit > 0 || offset > 0 {
		if limit > 0 {
			mods = append(mods, qm.Limit(limit))
		}
		if offset > 0 {
			mods = append(mods, qm.Offset(offset))
		}
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogTermRelationshipColumns.TermRelationshipID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogTermRelationships(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogTermRepository) Insert(
	ctx context.Context,
	term *model.BlogTerm,
	meta []*model.BlogTermMetum,
	extra *model.BlogExtra,
) error {
	if err := r.Conn(); err != nil {
		return err
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return err
	}

	err = term.Insert(ctx, tx, boil.Infer())
	if err != nil {
		tx.Rollback()
		return err
	}

	if len(meta) > 0 {
		for _, m := range meta {
			m.TermID = term.TermID
			err = m.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	if len(extra.Media) > 0 {
		for _, m := range extra.Media {
			m.ObjectID = term.TermID
			m.ObjectType = term.Taxonomy + enumx.PostTypeTermOffset
			err = m.Insert(ctx, tx, boil.Infer())
			if err != nil {
				tx.Rollback()
				return err
			}
		}
	}

	tx.Commit()
	return nil
}

func (r *customBlogTermRepository) Update(
	ctx context.Context,
	term *model.BlogTerm,
	meta []*model.BlogTermMetum,
	extra *model.BlogExtra,
) (int64, error) {
	if err := r.Conn(); err != nil {
		return 0, err
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return 0, err
	}

	termId, err := term.Update(ctx, tx, boil.Blacklist(
		model.BlogTermColumns.Count,
	))
	if err != nil {
		tx.Rollback()
		return 0, err
	}

	if len(meta) > 0 {
		for _, m := range meta {
			if m.MetaID > 0 {
				_, err = m.Update(ctx, tx, boil.Blacklist(
					model.BlogTermMetumColumns.MetaID,
					model.BlogTermMetumColumns.TermID,
				))
			} else {
				m.TermID = term.TermID
				err = m.Insert(ctx, tx, boil.Infer())
			}

			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}

	if len(extra.Media) > 0 {
		for _, m := range extra.Media {
			if m.AttachmentRelationshipID > 0 {
				_, err = m.Update(ctx, tx, boil.Blacklist(
					model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID,
					model.BlogAttachmentRelationshipColumns.ObjectID,
					model.BlogAttachmentRelationshipColumns.ObjectType,
					model.BlogAttachmentRelationshipColumns.AttachmentID,
				))
			} else {
				m.ObjectID = term.TermID
				m.ObjectType = term.Taxonomy + enumx.PostTypeTermOffset
				err = m.Insert(ctx, tx, boil.Infer())
			}
			if err != nil {
				tx.Rollback()
				return 0, err
			}
		}
	}

	if len(extra.DelMetaIds) > 0 {
		ids := make([]any, 0, len(extra.DelMetaIds))
		for _, id := range extra.DelMetaIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermMetumColumns.MetaID), ids...))
		_, err := model.BlogTermMeta(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}

	if len(extra.DelMediaIds) > 0 {
		ids := make([]any, 0, len(extra.DelMediaIds))
		for _, id := range extra.DelMediaIds {
			ids = append(ids, id)
		}
		var mods []qm.QueryMod
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID), ids...))
		_, err := model.BlogAttachmentRelationships(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}

	tx.Commit()
	return termId, nil
}

func (r *customBlogTermRepository) DeleteBatch(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	tx, err := r.mysqlConn.BeginTx(ctx, nil)
	if err != nil {
		return 0, err
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		values := make([]any, 0, len(ids))
		for _, id := range ids {
			values = append(values, id)
		}
		mods = append(mods, qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermColumns.TermID), values...))
		rowsAff, err = model.BlogTerms(mods...).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod := qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermMetumColumns.TermID), values...)
		_, err = model.BlogTermMeta(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}

		mod = qm.WhereIn(fmt.Sprintf("%s IN ?", model.BlogTermRelationshipColumns.TermID), values...)
		_, err = model.BlogTermRelationships(mod).DeleteAll(ctx, tx)
		if err != nil {
			tx.Rollback()
			return 0, err
		}
	}

	tx.Commit()
	return
}

func (r *customBlogTermRepository) GetMeta(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogTermMetum, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogTermMetumColumns.MetaID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermMetumColumns.MetaID, opMap)...)
			case model.BlogTermMetumColumns.TermID:
				mods = append(mods, modelx.GetIntMods(model.BlogTermMetumColumns.TermID, opMap)...)
			case model.BlogTermMetumColumns.MetaKey:
				mods = append(mods, modelx.GetStringMods(model.BlogTermMetumColumns.MetaKey, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.BlogTermMeta(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogTermMetumColumns.MetaID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogTermMeta(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogTermRepository) GetMedia(
	ctx context.Context,
	cols model.M,
	withCount int,
	filter map[string]map[string][]any,
) (list []*model.BlogAttachmentRelationship, count int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	var page int
	var pageSize int
	var selectCol string
	for k, v := range cols {
		switch k {
		case "page":
			if val, ok := v.(int64); ok && val > 1 {
				page = int(val)
			}
		case "pageSize":
			if val, ok := v.(int64); ok && val > 0 {
				pageSize = int(val)
			}
		case "orderBy":
			if val, ok := v.(string); ok && val != "" {
				mods = append(mods, qm.OrderBy(val))
			}
		case "select":
			if val, ok := v.(string); ok && val != "" {
				selectCol = val
			}
		}
	}

	if filter != nil {
		for key, opMap := range filter {
			switch key {
			case model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.ObjectID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.ObjectType:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.ObjectType, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentID:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentID, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentThumbnail:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentThumbnail, opMap)...)
			case model.BlogAttachmentRelationshipColumns.AttachmentOrder:
				mods = append(mods, modelx.GetIntMods(model.BlogAttachmentRelationshipColumns.AttachmentOrder, opMap)...)
			}
		}
	}

	if withCount >= 0 {
		count, err = model.BlogAttachmentRelationships(mods...).Count(ctx, r.mysqlConn)
		if err != nil {
			return
		}

		if withCount == 0 {
			return
		}
	}

	if pageSize > 0 {
		if page > 1 {
			mods = append(mods, qm.Offset(pageSize*(page-1)))
		}
		mods = append(mods, qm.Limit(pageSize))
	}

	var columns []string
	if selectCol != "" {
		if selectCol != "," {
			columns = strings.Split(selectCol, ",")
		}
		columns = append(columns, model.BlogAttachmentRelationshipColumns.AttachmentRelationshipID)
		columns = append(columns, model.BlogAttachmentRelationshipColumns.ObjectID)
	}
	if len(columns) > 0 {
		mods = append(mods, qm.Select(columns...))
	}

	list, err = model.BlogAttachmentRelationships(mods...).All(ctx, r.mysqlConn)
	return
}

func (r *customBlogTermRepository) IncreaseMeta(
	ctx context.Context,
	tids []int64,
	metaKey string,
	step int,
) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(tids) > 0 {
		termIds := make([]string, 0, len(tids))
		for _, tid := range tids {
			termIds = append(termIds, strconv.FormatInt(tid, 10))
		}
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s+%d where %s="%s" and %s in (%s)`,
			model.TableNames.BlogTermMeta,
			model.BlogTermMetumColumns.MetaValue,
			model.BlogTermMetumColumns.MetaValue,
			step,
			model.BlogTermMetumColumns.MetaKey,
			metaKey,
			model.BlogTermMetumColumns.TermID,
			strings.Join(termIds, ","),
		)).Bind(ctx, r.mysqlConn, &info)

		if err == sql.ErrNoRows {
			return model.ErrNotFound
		}
	}

	return
}

func (r *customBlogTermRepository) DecreaseMeta(ctx context.Context, tids []int64, metaKey string, step int) (err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(tids) > 0 {
		termIds := make([]string, 0, len(tids))
		for _, tid := range tids {
			termIds = append(termIds, strconv.FormatInt(tid, 10))
		}
		var info RandomInfo
		err = queries.Raw(fmt.Sprintf(
			`update %s set %s=%s-%d where %s="%s" and %s in (%s)`,
			model.TableNames.BlogTermMeta,
			model.BlogTermMetumColumns.MetaValue,
			model.BlogTermMetumColumns.MetaValue,
			step,
			model.BlogTermMetumColumns.MetaKey,
			metaKey,
			model.BlogTermMetumColumns.TermID,
			strings.Join(termIds, ","),
		)).Bind(ctx, r.mysqlConn, &info)

		if err == sql.ErrNoRows {
			return model.ErrNotFound
		}
	}

	return
}

func (r *customBlogTermRepository) DiagnoseMedia(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		mods = append(mods, model.BlogAttachmentRelationshipWhere.ObjectID.IN(ids))
		rowsAff, err = model.BlogAttachmentRelationships(mods...).DeleteAll(ctx, r.mysqlConn)
	}

	return
}

func (r *customBlogTermRepository) DiagnoseDetail(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		mods = append(mods, model.BlogKnowledgeBaseDetailWhere.DetailID.IN(ids))
		rowsAff, err = model.BlogKnowledgeBaseDetails(mods...).DeleteAll(ctx, r.mysqlConn)
	}

	return
}

func (r *customBlogTermRepository) DiagnoseMetum(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		mods = append(mods, model.BlogKnowledgeBaseMetumWhere.KnowledgeBaseID.IN(ids))
		rowsAff, err = model.BlogKnowledgeBaseMeta(mods...).DeleteAll(ctx, r.mysqlConn)
	}

	return
}

func (r *customBlogTermRepository) DiagnoseTerm(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		mods = append(mods, model.BlogTermRelationshipWhere.ObjectID.IN(ids))
		rowsAff, err = model.BlogTermRelationships(mods...).DeleteAll(ctx, r.mysqlConn)
	}

	return
}

func (r *customBlogTermRepository) DiagnoseRelationship(ctx context.Context, ids []uint64) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	if len(ids) > 0 {
		var mods []qm.QueryMod
		mods = append(mods, model.BlogKnowledgeBaseRelationshipWhere.EntryRelationshipID.IN(ids))
		rowsAff, err = model.BlogKnowledgeBaseRelationships(mods...).DeleteAll(ctx, r.mysqlConn)
	}

	return
}

func (r *customBlogTermRepository) SyncQiniu(ctx context.Context, id uint64, mediaId uint64, url string) (rowsAff int64, err error) {
	if err = r.Conn(); err != nil {
		return
	}

	var mods []qm.QueryMod
	mods = append(mods, model.BlogAttachmentRelationshipWhere.ObjectID.EQ(id))
	mods = append(mods, model.BlogAttachmentRelationshipWhere.AttachmentID.EQ(mediaId))
	list, err := model.BlogAttachmentRelationships(mods...).All(ctx, r.mysqlConn)
	if err != nil {
		return
	}

	if len(list) == 0 {
		return
	}

	urlStr := url+"?"+strconv.FormatInt(int64(mediaId), 10)

	for _, item := range list {
		if item.AttachmentSource == "" {
			continue
		}

		var subMods []qm.QueryMod
		switch enumx.PostType(item.ObjectType) {
		case enumx.PostTypeKnowledgeBase:
			subMods = append(subMods, model.BlogKnowledgeBaseDetailWhere.KnowledgeBaseID.EQ(item.ObjectID))
			subList, subErr := model.BlogKnowledgeBaseDetails(subMods...).All(ctx, r.mysqlConn)
			if subErr != nil {
				logrus.Info(fmt.Sprintf("SyncQiniu KnowledgeBaseDetail list error, entryId: %d, err: %+v", item.ObjectID, subErr))
				continue
			}

			for _, subItem := range subList {
				subItem.PostContent = strings.Replace(subItem.PostContent, item.AttachmentSource, urlStr, -1)
				subItem.PostContentFiltered = strings.Replace(subItem.PostContentFiltered, item.AttachmentSource, urlStr, -1)
				_, subErr = subItem.Update(ctx, r.mysqlConn, boil.Blacklist(
					model.BlogKnowledgeBaseDetailColumns.DetailID,
					model.BlogKnowledgeBaseDetailColumns.KnowledgeBaseID,
				))
				if subErr != nil {
					logrus.Info(fmt.Sprintf("SyncQiniu KnowledgeBaseDetail update error, entryId: %d, err: %+v", item.ObjectID, subErr))
				}
			}
		case enumx.PostTypePost:
			subMods = append(subMods, model.BlogPostDetailWhere.PostID.EQ(item.ObjectID))
			subList, subErr := model.BlogPostDetails(subMods...).All(ctx, r.mysqlConn)
			if subErr != nil {
				logrus.Info(fmt.Sprintf("SyncQiniu PostDetail list error, postId: %d, err: %+v", item.ObjectID, subErr))
				continue
			}

			for _, subItem := range subList {
				subItem.PostContent = strings.Replace(subItem.PostContent, item.AttachmentSource, urlStr, -1)
				subItem.PostContentFiltered = strings.Replace(subItem.PostContentFiltered, item.AttachmentSource, urlStr, -1)
				_, subErr = subItem.Update(ctx, r.mysqlConn, boil.Blacklist(
					model.BlogPostDetailColumns.DetailID,
					model.BlogPostDetailColumns.PostID,
				))
				if subErr != nil {
					logrus.Info(fmt.Sprintf("SyncQiniu PostDetail update error, postId: %d, err: %+v", item.ObjectID, subErr))
				}
			}
		case enumx.PostTypePage:
			subMods = append(subMods, model.BlogPageDetailWhere.PageID.EQ(item.ObjectID))
			subList, subErr := model.BlogPageDetails(subMods...).All(ctx, r.mysqlConn)
			if subErr != nil {
				logrus.Info(fmt.Sprintf("SyncQiniu PageDetail list error, pageId: %d, err: %+v", item.ObjectID, subErr))
				continue
			}

			for _, subItem := range subList {
				subItem.PostContent = strings.Replace(subItem.PostContent, item.AttachmentSource, urlStr, -1)
				subItem.PostContentFiltered = strings.Replace(subItem.PostContentFiltered, item.AttachmentSource, urlStr, -1)
				_, subErr = subItem.Update(ctx, r.mysqlConn, boil.Blacklist(
					model.BlogPageDetailColumns.DetailID,
					model.BlogPageDetailColumns.PageID,
				))
				if subErr != nil {
					logrus.Info(fmt.Sprintf("SyncQiniu PageDetail update error, pageId: %d, err: %+v", item.ObjectID, subErr))
				}
			}
		}
	}

	rowsAff, err = model.BlogAttachmentRelationships(mods...).UpdateAll(ctx, r.mysqlConn, model.M{
		model.BlogAttachmentRelationshipColumns.AttachmentImageURL: url,
	})

	return
}
